import { Component } from "react";
import axios from "axios";
import L from "leaflet";
import { Tree, message } from "antd";
import Loading from "../../../components/loading";
import Legend from "../../../components/legend";
import Tick from "./tick";
import { port, tileUrl, tiandituUrl, mapExtent, geoJsonUrl, layerStyle } from "../../../assets/global";
import enlargeSvg from "../../../assets/images/full-screen-exit.svg";
import shrinkSvg from "../../../assets/images/full-screen-enter.svg";
import "leaflet/dist/leaflet.css";
import style from "./index.module.css";

class Proj extends Component{
    constructor(props){
        super(props);
        this.state = {
            "checkedKeys": ["depth"],
            "isLoad": false,
            "isTick": false,
            "isLegend": {
                "sandFlow_N_10": false,
                "sandFlow_N_7": false,
                "sandFlow_year_average": false
            },
            "legend": {
                "sandFlow_N_10": { colors: [], lowVal: "", highVal: "" },
                "sandFlow_N_7": { colors: [], lowVal: "", highVal: "" },
                "sandFlow_year_average": { colors: [], lowVal: "", highVal: "" },
            },
            "tick": 0,
            "islarge": false       
        };

        this.onCheck = this.onCheck.bind(this);
        this.isShowLoading = this.isShowLoading.bind(this);
        this.setTick = this.setTick.bind(this);
        this.setLegend = this.setLegend.bind(this);
        this.enlarge = this.enlarge.bind(this);
        this.map = new Map(this.props.portName, this.props.proj, this.isShowLoading, this.setTick, this.setLegend);
    }

    componentDidMount(){
        this.map.init("map", port[this.props.portName].center, port[this.props.portName].zoom);
        this.map.setBaseLayer(this.props.proj);
    }

    componentDidUpdate(prevProps){
        if(prevProps.proj === this.props.proj){
            return;
        }
        this.map.refresh(this.props.portName, this.props.proj);
        this.map.setBaseLayer(this.props.proj);
        this.setState({
            "checkedKeys": ["depth"],
            "isLoad": false,
            "isTick": false,
            "isLegend": {
                "sandFlow_N_10": false,
                "sandFlow_N_7": false,
                "sandFlow_year_average": false
            }
        });
    }

    componentWillUnmount(){
        this.map.remove();
    }

    render(){
        let layers = port[this.props.portName]["projects"][this.props.proj].layers;
        let { islarge } = this.state;
        return (
            <div className={style["container"]}>
                <Loading size='large' masker={false} loading={this.state.isLoad}>
                    <div 
                        id={"map"} 
                        className={ islarge ? style["largeMapBox"] : style["smallMapBox"] } 
                        style={islarge ? {} : port[this.props.portName].containerStyle}
                    >
                        <img
                            src={islarge ? enlargeSvg : shrinkSvg}
                            alt="enlarge button"
                            className={style.enlargeBtn}
                            title={islarge ? "缩小" : "放大"}
                            onClick={this.enlarge}
                        />
                    </div>
                    <div className={style["layerTree"]}>
                        <Tree
                            checkable
                            defaultExpandAll
                            selectable={false}
                            treeData={layers}
                            checkedKeys={this.state.checkedKeys}
                            onCheck={this.onCheck}
                        />
                    </div>
                    {this.state.isTick ? (<Tick id={style["tick"]} tick={this.state.tick} />) : null}
                    <div className={style["legendBox"]}>
                        {this.state.isLegend.sandFlow_year_average && 
                            <Legend 
                                layerName="年平均" 
                                legendName="含沙量" 
                                {...this.state.legend.sandFlow_year_average} />
                        }
                        {this.state.isLegend.sandFlow_N_7 && 
                            <Legend 
                                layerName="七级中风天" 
                                legendName="含沙量" 
                                {...this.state.legend.sandFlow_N_7} />
                        }
                        {this.state.isLegend.sandFlow_N_10 && 
                            <Legend 
                                layerName="十级大风天" 
                                legendName="含沙量" 
                                {...this.state.legend.sandFlow_N_10} />
                        }
                    </div>
                </Loading>
            </div>
        );
    }

    onCheck(checkedKeys, e){
        this.setState({ checkedKeys });
        this.map.setSandFlow("sandFlow_N_10", checkedKeys.includes("sandFlow_N_10"));
        this.map.setSandFlow("sandFlow_N_7", checkedKeys.includes("sandFlow_N_7"));
        this.map.setSandFlow("sandFlow_year_average", checkedKeys.includes("sandFlow_year_average"));
        this.map.setWaterFlow(checkedKeys.includes("waterFlow"));
        this.map.setPlanChart(checkedKeys.includes("plan"));
        this.map.setBasin(checkedKeys.includes("basin"));
        this.map.setDepth(checkedKeys.includes("depth"));
        this.map.setOthers(checkedKeys.includes("others"));
        this.setState({
            "isTick": checkedKeys.includes("waterFlow"),
            "isLegend": {
                "sandFlow_N_10": checkedKeys.includes("sandFlow_N_10"),
                "sandFlow_N_7": checkedKeys.includes("sandFlow_N_7"),
                "sandFlow_year_average": checkedKeys.includes("sandFlow_year_average")
            }
        });
    }

    isShowLoading(isLoad){
        this.setState({ isLoad });
    }

    setTick(tick){
        this.setState({ tick });
    }

    setLegend(type, color, min, max){
        let { legend } = this.state;
        let col = color.replace("rgb", "rgba");
        legend[type] = {
            "colors": [col.replace(')', `, 1)`), col.replace(')', `, ${min / max})`)],
            "lowVal": min,
            "highVal": max
        };
        this.setState({ legend });
    }

    enlarge(){
        this.setState((prevState) => {
            return {
                islarge: !prevState.islarge
            }
        }, () => {
            this.map.map.invalidateSize();
        });
    }
} 

class Map{
    constructor(portName, proj, isShowLoading, setTick, setLegend){
        this.map = null;
        this.baseLayer = null;
        this.isShowLoading = isShowLoading;
        this.setTick = setTick;
        this.setLegend = setLegend;
        this.baseUrl = `${geoJsonUrl}/${portName}/${proj}`;     //基础路径
        this.layerGroup = null;
        this.sandFlow = {
            "sandFlow_N_10": null,                             //泥沙场十级大风天图层
            "sandFlow_N_7": null,                              //泥沙场七级大风天图层
            "sandFlow_year_average": null                      //泥沙场年平均图层
        };                        
        this.planChart = null;                                  //设计图图层
        this.basin = null;                                      //航道图层
        this.depth = null;                                      //等深线图层
        this.others = null;                                     //其他图层
        this.waterFlow = null;                                  //水流场图层
        this.waterFlowConf = {                                  //水流场图层相关的设置
            "timer": null,
            "data": [],
            "tick": 0,                                            //水流场时刻
            "total": 2700,                                        //总箭头数
            "ticks": 25                                           //时刻
        };
    }

    init(id, mapCenter, mapZoom){
        this.map = L.map(id, {
            crs: L.CRS.EPSG4326,
            minZoom: 0,
            maxZoom: 15,
            zoom: mapZoom,
            center: mapCenter,
            maxBounds: L.latLngBounds(L.latLng(mapExtent.lt.latitude, mapExtent.lt.longitude), L.latLng(mapExtent.rb.latitude, mapExtent.rb.longitude)),
            zoomControl: false,
            attributionControl: false
        });
        L.control.scale({ "imperial": false }).addTo(this.map);
        this.layerGroup = L.layerGroup().addTo(this.map);

        // this.map.on("click", e => {
        //     console.log(this.map.getCenter());
        //     console.log(this.map.getZoom());
        //     console.log(e);
        // });
    }

    setBaseLayer(proj){
        //工程前，加载2005年的卫星影像,其余年份加载2015年的卫星影像
        let year = proj === "preProj" ? 2005 : 2015;
        if(this.baseLayer){
            this.map.removeLayer(this.baseLayer);
        }
        this.setDepth(true);
        //this.baseLayer = L.tileLayer(`${tileUrl}/${year}/{x}/{y}/{z}`).addTo(this.map);
        this.baseLayer = L.tileLayer(tiandituUrl, { zoomOffset: 1, maxZoom: 15, "attribution": `2020年12月` }).addTo(this.map);
    }

    
    //泥沙场图层操作
    setSandFlow(type, state){
        let layer = this.sandFlow[type];
        if (!state && !this.layerGroup.hasLayer(layer)) {
            return;
        }
        if (!state && this.layerGroup.hasLayer(layer)) {
            this.layerGroup.removeLayer(layer);
            return;
        }
        if (state && this.layerGroup.hasLayer(layer)) {
            return;
        }
        if (state && !layer) {
            this.isShowLoading(true);
            axios.get(`${this.baseUrl}/${type}.json`).then(res => {
                let statistic = getSandFlowMax(res.data, "min");
                layer = L.geoJSON(res.data, {
                    "style": function (layer) {
                        return { ...layerStyle.sandFlow, "fillOpacity": parseFloat(layer.properties.min / statistic.max) };
                    }
                }).addTo(this.layerGroup);
                this.sandFlow[type] = layer;
                this.setLegend(type, layerStyle.sandFlow.color, statistic.min, statistic.max);
                this.isShowLoading(false);
            }, err => { this.loadErr(err) });
            return;
        }
        if (state && !this.layerGroup.hasLayer(layer)) {
            this.layerGroup.addLayer(layer);
        }
    }

    //设计图图层操作
    setPlanChart(state) {
        //未选中并且未显示图层
        if (!state && !this.layerGroup.hasLayer(this.planChart)) {
            return;
        }
        //未选中并且显示了图层，则移除图层
        if (!state && this.layerGroup.hasLayer(this.planChart)) {
            this.layerGroup.removeLayer(this.planChart);
            return;
        }
        //选中并且显示了图层
        if (state && this.layerGroup.hasLayer(this.planChart)) {
            return;
        }
        //选中并且图层不存在，则加载数据然后显示图层
        if (state && !this.planChart) {
            this.isShowLoading(true);
            this.planChart = L.featureGroup().addTo(this.layerGroup);
            axios.get(`${this.baseUrl}/plan.json`).then(res => {
                L.geoJSON(res.data, {
                    "style": () => layerStyle.plan
                }).addTo(this.planChart);
                this.isShowLoading(false);
            }, err => {
                this.loadErr(err);
            });
            return;
        }
        //选中、图层存在，但未显示，则显示图层
        if (state && !this.layerGroup.hasLayer(this.planChart)) {
            this.layerGroup.addLayer(this.planChart);
        }

    }
    //航道图层操作
    setBasin(state) {
        if (!state && !this.layerGroup.hasLayer(this.basin)) {
            return;
        }
        if (!state && this.layerGroup.hasLayer(this.basin)) {
            this.layerGroup.removeLayer(this.basin);
            return;
        }
        if (state && this.layerGroup.hasLayer(this.basin)) {
            return;
        }
        if (state && !this.basin) {
            this.isShowLoading(true);
            axios.get(`${this.baseUrl}/basin.json`).then(res => {
                this.basin = L.geoJSON(res.data, {
                    "style": () => layerStyle.basin
                }).addTo(this.layerGroup);
                this.isShowLoading(false);
            }, err => {
                this.loadErr(err);
            });
            return;
        }
        if (state && !this.layerGroup.hasLayer(this.basin)) {
            this.layerGroup.addLayer(this.basin);
        }
    }
    //等深线图层操作
    setDepth(state) {
        if (!state && !this.layerGroup.hasLayer(this.depth)) {
            return;
        }
        if (!state && this.layerGroup.hasLayer(this.depth)) {
            this.layerGroup.removeLayer(this.depth);
            return;
        }
        if (state && this.layerGroup.hasLayer(this.depth)) {
            return;
        }
        if (state && !this.depth) {
            this.isShowLoading(true);
            axios.get(`${this.baseUrl}/depth.json`).then(res => {
                let group = L.featureGroup();
                L.geoJSON(res.data, {
                    "style": function () {
                        return layerStyle.depth;
                    },
                    "onEachFeature": function (feature, layer) {
                        let index = parseInt(feature.geometry.coordinates.length / 2);
                        let icon = L.divIcon({
                            "html": feature.properties.value,
                            "className": layerStyle.depth.icon.className,
                            "interactive": false
                        });
                        if(feature.geometry.coordinates[index]){
                            L.marker(feature.geometry.coordinates[index].reverse(), { icon }).addTo(group);
                        }
                    }
                }).addTo(group);

                this.depth = group.addTo(this.layerGroup);
                this.isShowLoading(false);
            }, err => {
                this.loadErr(err);
            });
            return;
        }
        if (state && !this.layerGroup.hasLayer(this.depth)) {
            this.layerGroup.addLayer(this.depth);
        }
    }
    //其他图层
    setOthers(state) {
        if (!state && !this.layerGroup.hasLayer(this.others)) {
            return;
        }
        if (!state && this.layerGroup.hasLayer(this.others)) {
            this.layerGroup.removeLayer(this.others);
            return;
        }
        if (state && this.layerGroup.hasLayer(this.others)) {
            return;
        }
        if (state && !this.others) {
            this.others = L.featureGroup().addTo(this.map);
            let group = this.others;
            let temp = 3;
            axios.get(`${this.baseUrl}/others/area.json`).then((res) => {
                L.geoJSON(res.data, {
                    "style": layerStyle.others.area
                }).addTo(group);
                temp--;
                if (temp === 0) {
                    this.isShowLoading(false);
                }
            });
            axios.get(`${this.baseUrl}/others/coastline.json`).then((res) => {
                L.geoJSON(res.data, {
                    "style": function (geoJsonFeature) {
                        return { ...layerStyle.others.coastline, "color": layerStyle.others.coastline.colors[geoJsonFeature.properties.type] }
                    }
                }).addTo(group);
                temp--;
                if (temp === 0) {
                    this.isShowLoading(false);
                }
            });
            axios.get(`${this.baseUrl}/others/label.json`).then((res) => {
                let icon = null;
                res.data.features.forEach(f => {
                    icon = L.divIcon({
                        "html": f.properties.TextString,
                        "className": layerStyle.others.label.icon.className,
                        "interactive": false
                    });
                    L.marker(f.geometry.coordinates.reverse(), { icon }).addTo(group);
                });
                temp--;
                if (temp === 0) {
                    this.isShowLoading(false);
                }
            });
        }
        if (state && !this.layerGroup.hasLayer(this.others)) {
            this.layerGroup.addLayer(this.others);
        }
    }
    //水流场图层操作
    setWaterFlow(state) {
        if (!state && !this.layerGroup.hasLayer(this.waterFlow)) {
            return;
        }
        if (!state && this.layerGroup.hasLayer(this.waterFlow)) {
            clearInterval(this.waterFlowConf.timer);
            this.waterFlowConf.timer = null;
            this.layerGroup.removeLayer(this.waterFlow);
            return;
        }
        if (state && !this.waterFlow) {
            this.isShowLoading(true);
            let total = 0;
            let ticks = this.waterFlowConf.ticks;
            for (let i = 0; i < ticks; i++) {
                axios.get(`${this.baseUrl}/waterFlow/${i + 1}.txt`).then(res => {
                    let str = res.data;
                    let arr = str.split('\n');
                    this.waterFlowConf.data[i] = arr.map(item => {
                        return item.split(' ');
                    });
                    total++;
                    if (total === ticks) {
                        this.waterFlow = L.featureGroup();
                        for (let j = 0; j < this.waterFlowConf.total; j++) {
                            L.polyline([[0, 1], [0, 2], [0, 3], [0, 4], [0, 5]], layerStyle.waterFlow).addTo(this.waterFlow);
                        }
                        this.waterFlow.addTo(this.layerGroup);
                        this.startAnimation();
                        this.isShowLoading(false);
                    }
                }, err => { this.loadErr(err) });
            }
            return;
        }
        if (state && !this.layerGroup.hasLayer(this.waterFlow)) {
            this.layerGroup.addLayer(this.waterFlow);
            this.startAnimation();
        }
    }

    //开始水流场动画
    startAnimation() {
        this.waterFlowConf.timer = setInterval(() => {
            this.setTick(this.waterFlowConf.tick);
            let data = this.waterFlowConf.data[this.waterFlowConf.tick];
            let temp = 0;
            let num = 0;
            let len = data.length;
            this.waterFlow.eachLayer(ployline => {
                //如果总箭头数大于实际包含的箭头数，则多余箭头不做处理
                if (num >= len) {
                    return;
                }

                for (let j = 0; j < ployline._latlngs.length; j++) {
                    // if(Number(data[num][temp]) < 46000 && Number(data[num][temp + 1] < 58461)){
                    //   console.log(data[num][temp], data[num][temp + 1]);
                    // }
                    ployline._latlngs[j].lng = parseFloat(data[num][temp]);
                    temp++;
                    ployline._latlngs[j].lat = parseFloat(data[num][temp]);
                    temp++;
                }
                ployline.redraw();
                num++;
                temp = 0;
            });
            this.waterFlowConf.tick = (this.waterFlowConf.tick + 1) % this.waterFlowConf.ticks;
        }, 200);
    }

    //切换方案后，更新地图状态
    refresh(portName, proj) {
        //更新路径
        this.baseUrl = `${geoJsonUrl}/${portName}/${proj}`;
        //清空图层
        this.layerGroup.clearLayers();
        this.sandFlow = {
            "sandFlow_N_10": null,                             //泥沙场十级大风天图层
            "sandFlow_N_7": null,                              //泥沙场七级大风天图层
            "sandFlow_year_average": null                      //泥沙场年平均图层
        };
        this.planChart = null;                                  //设计图图层
        this.basin = null;                                      //航道图层
        this.depth = null;                                      //等深线图层
        this.waterFlow = null;                                  //水流场图层
        this.others = null;
        this.waterFlowConf.tick = 0;
        if (this.waterFlowConf.timer) {                           //清除水流场动画
            clearInterval(this.waterFlowConf.timer);
            this.waterFlowConf.timer = null;
        }
    }

    //加载数据失败
    loadErr(err) {
        this.isShowLoading(false);
        message.error("加载图层数据时出错！");
        console.log(err);
    }

    remove(){
        if (this.waterFlowConf.timer) {                           //销毁地图前，清除水流场动画
            clearInterval(this.waterFlowConf.timer);
            this.waterFlowConf.timer = null;
        }
        this.map.remove();
    }
}

//获取一个含沙量图层中含沙量最大值，最小值
function getSandFlowMax(data, type) {
    let arr = data.features.map(item => item.properties[type]);
    return {
        "min": Math.min.apply(Math, arr),
        "max": Math.max.apply(Math, arr)
    };
}

export default Proj;